home *** CD-ROM | disk | FTP | other *** search
/ Young Minds / Young Minds Interactive CD-ROM.ISO / qix / joystick.c next >
Encoding:
C/C++ Source or Header  |  1988-01-28  |  16.6 KB  |  588 lines

  1. #include "qix.h"
  2. #include "math.h"
  3.  
  4. /* the pen marker */
  5. short marker_curs_dat[] = {
  6. #include "marker.cursor"
  7. };
  8. mpr_static(pen_image,          16, 16, 1, marker_curs_dat);
  9.  
  10. short fast_draw_off_dat[] = {
  11. #include <images/mouse_left_hand.pr>
  12. };
  13. mpr_static(ms_fast_off,      16, 23, 1, fast_draw_off_dat);
  14.  
  15. short fast_draw_on_dat[] = {
  16. #include <images/mouse_left_hand_grey.pr>
  17. };
  18. mpr_static(ms_fast_on,     16, 23, 1, fast_draw_on_dat);
  19.  
  20. short slow_draw_off_dat[] = {
  21. #include <images/mouse_mid_hand.pr>
  22. };
  23. mpr_static(ms_slow_off,      16, 23, 1, slow_draw_off_dat);
  24.  
  25. short slow_draw_on_dat[] = {
  26. #include <images/mouse_mid_hand_grey.pr>
  27. };
  28. mpr_static(ms_slow_on,     16, 23, 1, slow_draw_on_dat);
  29.  
  30. /* joystick (really, arrow) symbols */
  31. short left_arrow_dat[] = {
  32. #include "joystick.lf"
  33. };
  34. mpr_static(joystick_left,   64, 64, 1, left_arrow_dat);
  35.  
  36. short right_arrow_dat[] = {
  37. #include "joystick.rt"
  38. };
  39. mpr_static(joystick_right,  64, 64, 1, right_arrow_dat);
  40.  
  41. short up_arrow_dat[] = {
  42. #include "joystick.up"
  43. };
  44. mpr_static(joystick_up,     64, 64, 1, up_arrow_dat);
  45.  
  46. short dn_arrow_dat[] = {
  47. #include "joystick.dn"
  48. };
  49. mpr_static(joystick_down,   64, 64, 1, dn_arrow_dat);
  50.  
  51. /* a circle with line thru it */
  52. short stop_dat[] = {
  53. #include "joystick.stop"
  54. };
  55. mpr_static(joystick_stop,   64, 64, 1, stop_dat);
  56.  
  57. /* a big right mouse button */
  58. short ready_icon_dat[] = {
  59. #include "mouse.rt.icon"
  60. };
  61. mpr_static(ready_icon,      64, 64, 1, ready_icon_dat);
  62.  
  63. /*
  64.  * the main window selection catches input interrupts and calls this
  65.  * routine to process what just happened.  Nothing is actually done
  66.  * besides that -- that is, the pen is not moved, the qix isn't moved,
  67.  * and sparks don't move.  however, we will reset the "moving" variable,
  68.  * start the or finish the "drawing" state, and reset the icon that displays
  69.  * the joystick icon that indicates which way the user is moving.
  70.  */
  71. move_joystick(canvas, event, data)
  72. register Canvas canvas;
  73. register Event *event;
  74. {
  75.     register int ID = event->ie_code;
  76.     static start_fast;
  77.  
  78.     if (play_mode != REAL_PLAY && ID != ' ' && ID != MS_RIGHT)
  79.     return;
  80.  
  81.     if ((ID == LOC_MOVE) && moving != NO_MOVE) {
  82.     register int delta_x, delta_y;
  83.     if (event_x(event) <= 0)
  84.         event_set_x(event, 1);
  85.     if (event_y(event) <= 0)
  86.         event_set_y(event, 1);
  87.     delta_x = event_x(event) - MID_X;
  88.     delta_y = event_y(event) - MID_Y;
  89.  
  90.     /* didn't move enough */
  91.     if (abs(delta_x) <= SENS_FACTOR && abs(delta_y) <= SENS_FACTOR)
  92.         return;
  93.  
  94.     if (abs(delta_x) > abs(delta_y))
  95.         if (delta_x > 0)
  96.         moving = RIGHT;
  97.         else
  98.         moving = LEFT;
  99.     else
  100.         if (delta_y > 0)
  101.         moving = DOWN;
  102.         else
  103.         moving = UP;
  104.     }
  105.  
  106.     if (isascii(ID) && ID != ' ') {
  107. #ifdef DEBUG
  108.     if (isdigit(ID)) {
  109.         debug = ID - '0';
  110.         msg("Debugging level set to %d", debug);
  111.         sleep(2);
  112.         remove_msgs();
  113.         return;
  114.     } else
  115. #endif DEBUG
  116.     if (event_is_up(event)) {
  117.         /* up events -- user released a key, so stop moving */
  118.         /* unimplemented -- holding key down results in fast up/down's */
  119.         moving = STOP;
  120.         drawing = 0;
  121.         return;
  122.     } else if (event_shift_is_down(event))
  123.         fast = drawing = 1;
  124.     else if (event_meta_is_down(event))
  125.         fast = !(drawing = 1);
  126.     else
  127.         drawing = 0;
  128.     }
  129.  
  130.     switch(ID) {
  131.     when MS_LEFT :
  132.         fast = (drawing = (!event_is_up(event)));
  133.         start_fast = TRUE;
  134.         return;
  135.     when MS_MIDDLE :
  136.         fast = 0;
  137.         if (start_fast == TRUE && region)
  138.         drawing = 0;
  139.         else
  140.         drawing = !event_is_up(event);
  141.         return;
  142.     when MS_RIGHT : case ' ' :
  143.         if (event_is_up(event))
  144.         break;
  145.         /* if moving == NO_MOVE, RIGHT, LEFT, UP or DOWN */
  146.         if (!is_alive || play_mode != REAL_PLAY) {
  147.         lives = 0;
  148.         play_mode = REAL_PLAY;  /* set Nowhere else but here! */
  149.         change_life(LIVE); /* "next" life in current game */
  150.         } else if (moving != STOP) {
  151.         /* NO_MOVE state goes right to STOP state */
  152.         if (moving == NO_MOVE)
  153.             reset_joystick_win(FALSE);
  154.         /* all other directions go right to STOP state */
  155.         moving = STOP;
  156.         } else
  157.         /* STOP state goes right to NO_MOVE state */
  158.         moving = NO_MOVE, reset_joystick_win(TRUE);
  159.     when 'h' : case 'H' : case KEY_RIGHT(10) :
  160.         moving = LEFT;
  161.     when 'l' : case 'L' : case KEY_RIGHT(12) :
  162.         moving = RIGHT;
  163.     when 'j' : case 'J' : case KEY_RIGHT(14) :
  164.         moving = DOWN;
  165.     when 'k' : case 'K' : case KEY_RIGHT(8) :
  166.         moving = UP;
  167.     when LOC_MOVE : break; /* let those thru! */
  168. #ifdef DEBUG
  169.     case '@' : no_qix_kill = !no_qix_kill; drawing = 0;
  170.     when '#' : clear_sparks();
  171.     when '+' : lives = min(lives+1, MAX_LIVES); update_score(); drawing = 0;
  172.     when '-' : lives = max(lives-1, 1); update_score(); drawing = 0;
  173.     when '!' : drawing = 0;
  174.         if (play_mode == REAL_PLAY) {
  175.         lives = 0;
  176.         change_life(LIVE);
  177.         } /* fall thru */
  178. #endif DEBUG
  179.     default :
  180.         return; /* do nothing */
  181.     }
  182.     if (moving != NO_MOVE &&
  183.     (event_x(event) != MID_X || event_y(event) != MID_Y))
  184.     window_set(canvas, WIN_MOUSE_XY, MID_X, MID_Y, 0);
  185. }
  186.  
  187. /*
  188.  * The main routine waits for input from the user until an alarm goes off
  189.  * which says, "ok, go to the next state of the machine" which may very
  190.  * well be "do nothing".  The timer is restarted when we're done processing
  191.  * whatever we have to process.  This is where the pen actually moves to the
  192.  * next position, drawing lines, or running scared from a vicious spark.
  193.  */
  194. move_pen()
  195. {
  196.     register int x = pen_x, y = pen_y, new_value, old_value;
  197.     static slow_draw;
  198.  
  199.     if (!is_alive && lives > 0) {
  200.     /* user has died and is waiting to start again */
  201.     sleep(2);
  202.     change_life(LIVE);
  203.     stop_timer(); /* change_life restarts it */
  204.     msg("Ready?");
  205.     sleep(2);
  206.     remove_msgs(0);
  207.     start_timer();
  208.     return;
  209.     }
  210.     /* don't play if the joystick isn't active */
  211.     if (moving == NO_MOVE || play_mode != REAL_PLAY) {
  212.     if (play_mode != REAL_PLAY) {
  213.         time_left--;
  214.         if (play_mode == DEMO && lives > 0) {
  215.         if (time_left == 0) {
  216.             int lastmove = moving;
  217.             register int left, right, up, down;
  218.             drawing = 1;
  219.             if (!(board[x][y] & NEW_LINE))
  220.             fast = (rrand() & 3);
  221.             left = (!check_painted(x, y, CL_PNT_LEFT) &&
  222.                 !(board[x-1][y] & NEW_LINE));
  223.  
  224.             right = (!check_painted(x, y, CL_PNT_RIGHT) &&
  225.                  !(board[x+1][y] & NEW_LINE));
  226.  
  227.             up = (!check_painted(x, y, CL_PNT_TOP) &&
  228.               !(board[x][y-1] & NEW_LINE));
  229.  
  230.             down = (!check_painted(x, y, CL_PNT_BOT) &&
  231.                 !(board[x][y+1] & NEW_LINE));
  232.  
  233.             if (!left && !right && !up && !down)
  234.             moving = STOP, time_left = -1; /* let fuse catch up */
  235.             else {
  236.             int dx = region ? region->x - x : 0;
  237.             int dy = region ? region->y - y : 0;
  238.             time_left = 15 + (rrand() & 31);
  239.             /* first attempt to limit box to less than 25 X 25 */
  240.             if (region && (_ABS(dx) > 25 || _ABS(dy) > 25)) {
  241.                 if (_ABS(dx) > 25 ||
  242.                 _ABS(dy) > 25 && (moving == LEFT ||
  243.                           moving == RIGHT))
  244.                 if (moving != LEFT && moving != RIGHT)
  245.                     moving = (dx > 25) ? RIGHT : LEFT;
  246.                 else
  247.                     moving = (dy > 0) ? DOWN : UP;
  248.                 else if (_ABS(dy) > 25)
  249.                 if (moving != UP && moving != DOWN)
  250.                     moving = (dy > 25) ? DOWN : UP;
  251.                 else
  252.                     moving = (dx > 0) ? RIGHT : LEFT;
  253.             }
  254.             /* Make sure we can move in that direction */
  255.             while (moving == lastmove ||
  256.                 !left && moving == LEFT || !up && moving == UP ||
  257.                 !down && moving == DOWN || !right && moving== RIGHT)
  258.                 moving = LEFT + (rrand() & 3);
  259.             }
  260.         }
  261.         } else if (time_left <= 0) {
  262.         drawing = 0;
  263.         level = -2;
  264.         moving = NO_MOVE;
  265.         init_qix();
  266.         switch (play_mode = (play_mode + 1) % (DEMO+1)) {
  267.             when SHOW_SCORES :
  268.             clear_board();
  269.             score_board(TRUE, FALSE);
  270.             time_left = 50;
  271.             when SHOW_POINTS :
  272.             score = 0;
  273.             update_score();
  274.             move_fuse(fuse = NULL); /* just in case */
  275.             rm_cur_line(PIX_CLR);
  276.             clear_board();
  277.             place_pen();
  278.             msg("Direct the mouse to control joystick.");
  279.             time_left = 315;
  280.             moving = LEFT;
  281.             when SHOW_QIX :
  282.             remove_msgs(0);
  283.             msg("Your Enemies:");
  284.             sleep(2);
  285.             time_left = 40;
  286.             when SHOW_SPARKS :
  287.             time_left = 90;
  288.             when SHOW_FUSE :
  289.             drawing = fast = 1;
  290.             moving = UP;
  291.             time_left = 280;
  292.             when SHOW_SPIRAL :
  293.             moving = STOP;
  294.             drawing = 0;
  295.             time_left = 100;
  296.             when DEMO :
  297.             time_left = 1;
  298.             change_life(LIVE);
  299.             stop_timer();
  300.         msg("Enclose more than\n75%%\nof the play area for extra bonus.");
  301.             sleep(2);
  302.             remove_msgs(0);
  303.             level = -2;
  304.             drawing = fast = 1;
  305.             goto done;
  306.         }
  307.         } else switch (play_mode) {
  308.         when SHOW_QIX :
  309.             move_qix();
  310.             if (time_left == 1) {
  311.             pw_text(draw_win, 200,200,PIX_SRC,big_font, "The qix.");
  312.             sleep(2);
  313.             }
  314.         when SHOW_SPARKS :
  315.             move_sparks();
  316.             if (time_left == 1) {
  317.             pw_text(draw_win, 15, 110, PIX_SRC, big_font, "Sparx.");
  318.             pw_text(draw_win,625, 110, PIX_SRC, big_font, "Sparx.");
  319.             sleep(2);
  320.             }
  321.         when SHOW_FUSE :
  322.             /* after the pw_text, this moves into spiral death trap */
  323.             switch (time_left) {
  324.             when 230 :
  325.                 drawing = 0;
  326.                 pw_text(draw_win,
  327.                 convert_x(pen_x - 7), convert_y(pen_y + 7),
  328.                 PIX_SRC, big_font, "The fuse.");
  329.             when 80 :
  330.                 pw_text(draw_win, 265, 445,
  331.                 PIX_SRC, big_font, "The Spiral Death Trap.");
  332.             case 200 : case 240 : case 40 : case 20 :
  333.                 moving = LEFT, drawing = 1;
  334.             when 110 : case  55 : case 30 : moving = RIGHT;
  335.             when 126 : case  65 : case 35 : moving = UP;
  336.             when  95 : case  45 : case 25 : moving = DOWN;
  337.             }
  338.             goto movit;
  339.         when SHOW_SPIRAL :
  340.             if (fuse) { /* when we die, fuse will be NULL */
  341.             time_left = 2;
  342.             goto movit;
  343.             } else if (region) {
  344.             move_fuse(fuse = NULL);
  345.             rm_cur_line(PIX_SRC);
  346.             }
  347.         when SHOW_POINTS : {
  348.             char buf[5];
  349.             switch (time_left) {
  350.             when 270 :
  351.                 msg("Use LEFT mouse button for Fast Draw.");
  352.                 drawing = fast = 1, moving = UP;
  353.                 score = 0;
  354.             when 170 :
  355.                 msg("Use MIDDLE mouse button for Slow Draw.");
  356.                 drawing = 1, fast = 0, moving = UP;
  357.                 score = 0;
  358.             when 250 : case 130 : moving = RIGHT;
  359.             when 230 : case  90 : moving = DOWN;
  360.             when 210 : drawing = 0, moving = RIGHT;
  361.                 pw_text(draw_win,
  362.                 convert_x(pen_x - 12), convert_y(pen_y - 25),
  363.                 PIX_SRC, big_font, sprintf(buf, "%d", score));
  364.             when 49 : /* make sure region is closed */
  365.                 msg("Use RIGHT mouse button to STOP movement.");
  366.                 pw_text(draw_win,
  367.                 convert_x(pen_x - 12), convert_y(pen_y - 25),
  368.                 PIX_SRC, big_font, sprintf(buf, "%d", score));
  369.             when 15 : drawing = 0, moving = RIGHT;
  370.             }
  371.             goto movit; /* avoid moving qix and sparks */
  372.         }
  373.         }
  374.     }
  375.     if (play_mode != DEMO)
  376.         goto done;
  377.     }
  378.  
  379.     if (move_qix() == -1) {
  380.     change_life(DIE);
  381.     return;
  382.     }
  383.  
  384.     if (move_sparks() == -1) /* player got hosed */
  385.     return; /* don't restart timer */
  386.  
  387. movit:
  388.     draw_joystick();
  389.     if (moving == STOP) {
  390.     if (!cur_coord || move_fuse(&fuse) != -1)  /* -1: fuse caught up */
  391.         start_timer();
  392.     return;
  393.     }
  394.     /* this forces the last fuse to go away */
  395.     (void) move_fuse((struct region *)NULL); /* this can't return -1 */
  396.     if (drawing && !fast && board[pen_x][pen_y] & NEW_LINE
  397.     && (slow_draw = !slow_draw))
  398.     goto done;
  399.  
  400.     /*
  401.      * x,y will be the new (proposed) position if the following is true...
  402.      * if not drawing, then check to see if the current cell we're at connects
  403.      * with the proposed new position.  Logic says that it will connect if
  404.      * it "points" that way.. f'rinstance, you can't move left if the current
  405.      * cell doesn't have the "cell-line-left" (CL_LN_LF) attribute. Also,
  406.      * check to see if the current cell has the NEW_LINE attribute. If so,
  407.      * user should be drawing. If he isn't, the fuse starts.
  408.      */
  409.     switch (moving) {
  410.     when LEFT :
  411.         if (check_painted(x, y, CL_PNT_LEFT) ||
  412.             !drawing && !(board[x][y] & (CL_LN_LF|NEW_LINE))) {
  413.         if (play_mode == DEMO)
  414.             time_left = 1;
  415.         goto done;
  416.         }
  417.         x--;
  418.     when RIGHT :
  419.         if (check_painted(x, y, CL_PNT_RIGHT) ||
  420.             !drawing && !(board[x][y] & (CL_LN_RT|NEW_LINE))) {
  421.         if (play_mode == DEMO)
  422.             time_left = 1;
  423.         goto done;
  424.         }
  425.         x++;
  426.     when UP :
  427.         if (check_painted(x, y, CL_PNT_TOP) ||
  428.             !drawing && !(board[x][y] & (CL_LN_UP|NEW_LINE))) {
  429.         if (play_mode == DEMO)
  430.             time_left = 1;
  431.         goto done;
  432.         }
  433.         --y;
  434.     when DOWN :
  435.         if (check_painted(x, y, CL_PNT_BOT) ||
  436.             !drawing && !(board[x][y] & (CL_LN_DN|NEW_LINE))) {
  437.         if (play_mode == DEMO)
  438.             time_left = 1;
  439.         goto done;
  440.         }
  441.         ++y;
  442.     }
  443.     old_value = board[pen_x][pen_y];
  444.     new_value = board[x][y];
  445.     /*
  446.      * If drawing, you can't move onto yourself (a "new" line). [start fuse]
  447.      * You can alwasy move onto an old line (completing a region if drawing).
  448.      * If not drawing, you must be on an old line and moving
  449.      * onto another old line. If we're not drawing and *should* be drawing
  450.      * (determined by old_value's NEW_LINE bit set), start a fuse.
  451.      * Also, player can't cheat by fast drawing and suddenly changing to
  452.      * a slow draw just to close a region. Test to see if start_fast is
  453.      * set correctly by testing "region" first.
  454.      */
  455.     if (drawing && (new_value & NEW_LINE) && !(new_value & OLD_LINE) ||
  456.     !drawing && (old_value & NEW_LINE)) {
  457.     if (!fuse) /* if a fuse isn't going, ignite one */
  458.         fuse = region;
  459.     if (play_mode == DEMO)
  460.         time_left = 1;
  461.     else
  462.         moving = STOP;
  463.     goto done;
  464.     }
  465.  
  466.     /* erase the pen_image, move, reset pen_image, draw line */
  467.     place_pen();
  468.  
  469.     /* next, determine that if we are drawing, ignore that fact if we
  470.      * are attempting to draw on top of an already drawn line.  If we
  471.      * are creating a new line, then go ahead and create it.
  472.      */
  473.     if (drawing) {
  474.     switch (moving) {
  475.         when LEFT :
  476.         if (board[pen_x][pen_y] & CL_LN_LF)
  477.             goto redraw_pen;
  478.         board[pen_x][pen_y] |= CL_LN_LF;
  479.         board[x][y] |= CL_LN_RT;
  480.         when RIGHT :
  481.         if (board[pen_x][pen_y] & CL_LN_RT)
  482.             goto redraw_pen;
  483.         board[pen_x][pen_y] |= CL_LN_RT;
  484.         board[x][y] |= CL_LN_LF;
  485.         when UP :
  486.         if (board[pen_x][pen_y] & CL_LN_UP)
  487.             goto redraw_pen;
  488.         board[pen_x][pen_y] |= CL_LN_UP;
  489.         board[x][y] |= CL_LN_DN;
  490.         when DOWN :
  491.         if (board[pen_x][pen_y] & CL_LN_DN)
  492.             goto redraw_pen;
  493.         board[pen_x][pen_y] |= CL_LN_DN;
  494.         board[x][y] |= CL_LN_UP;
  495.     }
  496.     draw(convert_x(x), convert_y(y),
  497.          convert_x(pen_x), convert_y(pen_y), PIX_SRC);
  498.     if (!region) {
  499.         saved_edge = old_value;
  500.         add_to_line(pen_x, pen_y);
  501.         old_value = (board[pen_x][pen_y] |= NEW_LINE);
  502.     }
  503.     /* if drawing from a newline onto an old line, a region is completed */
  504.     if ((old_value & NEW_LINE) && (new_value & OLD_LINE)) {
  505.         int new_level = close_region(x, y);
  506.         if (!new_level)
  507.         update_score();
  508.         if (new_level || (int)(((double)area_closed/TOTAL_AREA)*100) >= 75){
  509.         if (!new_level) {
  510.             int percent_closed =
  511.             (int)(((double)area_closed/TOTAL_AREA) * 100);
  512.             msg("Closed %d%% of the board.", percent_closed);
  513.             if (percent_closed > 75) {
  514.             score += (percent_closed - 75) * 1000;
  515.             update_score();
  516.             msg("1000 bonus points for each percent over 75%%");
  517.             msg("BONUS: %d", (percent_closed - 75) * 1000);
  518.             }
  519.         } else
  520.             level++;
  521.         sleep(3);
  522.         clear_board(); /* removes msgs also */
  523.         change_life(LIVE);
  524.         stop_timer();
  525.         if (level < 0)
  526.             level++;
  527.         if (level == 0) {
  528.             msg("Split the 2 qix to advance score multiplier.");
  529.             sleep(2);
  530.             remove_msgs(0);
  531.         }
  532.         start_timer();
  533.         return;
  534.         }
  535.     } else if (new_value == 0) {
  536.         board[x][y] |= NEW_LINE;
  537.         add_to_line(x, y);
  538.     }
  539.     }
  540. redraw_pen:
  541.     pen_x = x, pen_y = y;
  542.     place_pen(); /* set the new pen image */
  543. done:
  544.     start_timer();
  545. }
  546.  
  547. draw_joystick()
  548. {
  549.     Pixrect *image = moving == LEFT? &joystick_left :
  550.              moving == RIGHT? &joystick_right :
  551.              moving == UP? &joystick_up :
  552.              moving == DOWN? &joystick_down :
  553.              moving == STOP? &joystick_stop : &ready_icon;
  554.     pw_rop(joystick_win,
  555.     BOARD_WIDTH_IN_PIXELS/2-32, 2, 64, 64, PIX_SRC, image, 0,0);
  556.     pw_rop(joystick_win, 100,32, 16,23, PIX_SRC,
  557.     (drawing && fast)? &ms_fast_on : &ms_fast_off, 0, 0);
  558.     pw_rop(joystick_win, 150,32, 16,23, PIX_SRC,
  559.     (drawing && !fast)? &ms_slow_on : &ms_slow_off, 0, 0);
  560. }
  561.  
  562. /*
  563.  * if "see_it" -- then show the mouse cursor and stop moving mouse to middle
  564.  * of window allowing allow player to grab beer. If "see_it" is
  565.  * false, then the user is ready to move around, so make cursor go away,
  566.  * and force all mouse moves to return to the middle of window.
  567.  */
  568. reset_joystick_win(see_it)
  569. {
  570.     static int oldop;
  571.  
  572.     Cursor cursor = (Cursor)window_get(Draw, WIN_CURSOR);
  573.  
  574.     if (!see_it) {   /* we don't want to see the cursor, so get rid of it */
  575.     /* get the current cursor and make it invisible */
  576.     oldop = (int)cursor_get(cursor, CURSOR_OP);
  577.     cursor_set(cursor, CURSOR_OP, PIX_DST, 0);
  578.     moving = STOP;
  579.     draw_joystick();
  580.     } else {
  581.     /* cursor_set(cursor, CURSOR_OP, oldop, 0); */
  582.     moving = NO_MOVE;
  583.     draw_joystick();
  584.     }
  585.     window_set(Joystick, WIN_CURSOR, cursor, 0);
  586.     window_set(Draw, WIN_CURSOR, cursor, 0);
  587. }
  588.